package com.fernandomartines.dbcheck.app.controller;

import com.fernandomartines.dbcheck.app.model.TestCaseTableModel;
import com.fernandomartines.dbcheck.app.view.DBCheckView;
import com.fernandomartines.dbcheck.app.view.TestCaseFormView;
import com.fernandomartines.dbcheck.app.view.TestCaseGenerationView;
import com.fernandomartines.dbcheck.app.view.TestSuiteContentView;
import com.fernandomartines.dbcheck.app.view.TestSuiteFormView;
import com.fernandomartines.dbcheck.app.view.TestSuiteItemTemplateView;
import com.fernandomartines.dbcheck.logger.LoggerOutputStream;
import com.fernandomartines.dbcheck.test.entities.TestCase;
import com.fernandomartines.dbcheck.test.entities.TestCycle;
import com.fernandomartines.dbcheck.test.entities.TestExecutionObserver;
import com.fernandomartines.dbcheck.test.entities.TestLog;
import com.fernandomartines.dbcheck.test.entities.TestResult;
import com.fernandomartines.dbcheck.test.entities.TestSuite;
import com.fernandomartines.dbcheck.test.entities.TestSuites;
import com.fernandomartines.dbcheck.test.services.TestDriver;
import com.fernandomartines.dbcheck.test.services.TestGenerator;
import com.fernandomartines.dbcheck.test.services.TestService;
import com.fernandomartines.dbcheck.util.DialogUtil;
import com.fernandomartines.dbcheck.util.ScreenUtil;
import com.fernandomartines.dbcheck.util.StringUtil;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.PrintStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Date;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;

public class DBCheckController 
        implements ActionListener, ListSelectionListener, TestExecutionObserver
{

    public enum Operation {
        INSERT, UPDATE, DELETE, UNDEFINED;
    }
    private Operation currentOperation = Operation.UNDEFINED;

    private final String JDBC_CLASS_TEMPLATE = "com.mysql.jdbc.Driver";
    private final String JDBC_URL_TEMPLATE = "jdbc:mysql://localhost:3306/wp";

    private final String CREATE_TEST_SUITE_ACTION = "CreateTestSuiteAction";
    private final String TEST_CONNECTION_ACTION = "TestConnectionAction";
    private final String OPEN_XMI_FILE_ACTION = "OpenXMIFileAction";
    private final String SAVE_TEST_SUITE_ACTION = "SaveTestSuiteAction";
    private final String CANCEL_TEST_SUITE_ACTION = "CancelTestSuiteAction";
    private final String EDIT_TEST_SUITE_ACTION = "EditTestSuiteAction";
    private final String DELETE_TEST_SUITE_ACTION = "DeleteTestSuiteAction";
    private final String GENERATE_TEST_CASES_ACTION = "GenerateTestCasesAction";
    private final String EXECUTE_TEST_CASES_ACTION = "ExecuteTestCases";
    private final String TEST_CASE_GENERATION_DONE_ACTION = "TestCaseGenerationDoneAction";
    private final String SAVE_TEST_CASE_ACTION = "SaveTestCaseAction";
    private final String CANCEL_TEST_CASE_ACTION = "CancelTestCaseAction";
    // windows
    private JFrame testCaseFormWindow;
    private JFrame testSuiteFormWindow;
    private JFrame testCaseGenerationWindow;
    // views
    private DBCheckView mainView;
    private TestCaseFormView testCaseFormView;
    private TestSuiteFormView testSuiteFormView;
    private TestSuiteContentView testSuiteContentView;
    private TestCaseGenerationView testCaseGenerationView;
    // entities
    private TestSuites testSuites;
    private TestSuite testSuite;
    private TestCase testCase;
    // services
    private TestGenerator testGenerator;
    private TestService testService;
    private TestDriver testDriver;

    public DBCheckController(DBCheckView mainView) {
        this.mainView = mainView;

        createServices();
        createViews();

        registerActions();

        loadTestSuites();
    }

    public void createServices() {
        this.testService = new TestService();
        this.testDriver = new TestDriver();
        this.testDriver.addTestExecutionObserver(this);
    }

    public void createViews() {
        testCaseFormView = new TestCaseFormView();
        testSuiteFormView = new TestSuiteFormView();
        testSuiteContentView = new TestSuiteContentView();
        testCaseGenerationView = new TestCaseGenerationView();
        testCaseFormWindow = new JFrame();
    }

    public void registerActions() {
        mainView.getButtonCreateTestSuite().setActionCommand(CREATE_TEST_SUITE_ACTION);
        testCaseFormView.getButtonSave().setActionCommand(SAVE_TEST_CASE_ACTION);
        testCaseFormView.getButtonCancel().setActionCommand(CANCEL_TEST_CASE_ACTION);
        testSuiteFormView.getButtonOpenXMIFile().setActionCommand(OPEN_XMI_FILE_ACTION);
        testSuiteFormView.getButtonTestConnection().setActionCommand(TEST_CONNECTION_ACTION);
        testSuiteFormView.getButtonSave().setActionCommand(SAVE_TEST_SUITE_ACTION);
        testSuiteFormView.getButtonCancel().setActionCommand(CANCEL_TEST_SUITE_ACTION);
        testSuiteContentView.getButtonEdit().setActionCommand(EDIT_TEST_SUITE_ACTION);
        testSuiteContentView.getButtonDelete().setActionCommand(DELETE_TEST_SUITE_ACTION);
        testSuiteContentView.getButtonExecuteTestCases().setActionCommand(EXECUTE_TEST_CASES_ACTION);
        testSuiteContentView.getButtonGenerateTestCases().setActionCommand(GENERATE_TEST_CASES_ACTION);
        testCaseGenerationView.getButtonAction().setActionCommand(TEST_CASE_GENERATION_DONE_ACTION);

        mainView.getButtonCreateTestSuite().addActionListener(this);
        testCaseFormView.getButtonSave().addActionListener(this);
        testCaseFormView.getButtonCancel().addActionListener(this);
        testSuiteFormView.getButtonOpenXMIFile().addActionListener(this);
        testSuiteFormView.getButtonTestConnection().addActionListener(this);
        testSuiteFormView.getButtonSave().addActionListener(this);
        testSuiteFormView.getButtonCancel().addActionListener(this);
        testSuiteContentView.getButtonEdit().addActionListener(this);
        testSuiteContentView.getButtonDelete().addActionListener(this);
        testSuiteContentView.getButtonExecuteTestCases().addActionListener(this);
        testSuiteContentView.getButtonGenerateTestCases().addActionListener(this);
        testCaseGenerationView.getButtonAction().addActionListener(this);
    }

    public void openTestSuiteWindow(Operation operation) {
        this.currentOperation = operation;

        String title = operation == Operation.INSERT
                ? "Adding New Test Suite" : "Editing Test Suite";

        testSuiteFormWindow = new JFrame(title);
        testSuiteFormWindow.setBounds(250, 250, 1000, 700);
        testSuiteFormWindow.setIconImage(mainView.getFrame().getIconImage());
        testSuiteFormWindow.getContentPane().add(testSuiteFormView, BorderLayout.CENTER);
        testSuiteFormWindow.setResizable(false);
        testSuiteFormWindow.setVisible(true);
        ScreenUtil.centralizeFrame(testSuiteFormWindow);

        if (operation == Operation.INSERT)
            emptyTestSuiteForm();
        else
            fillTestSuiteForm();
    }

    public void closeTestSuiteWindow() {
        testSuiteFormWindow.setVisible(false);
    }

    public void openTestCaseWindow() {
        String title = "Editing Test Case";

        testCaseFormWindow.setTitle(title);
        testCaseFormWindow.setBounds(250, 250, 1000, 600);
        testCaseFormWindow.setIconImage(mainView.getFrame().getIconImage());
        testCaseFormWindow.getContentPane().add(testCaseFormView, BorderLayout.CENTER);
        testCaseFormWindow.setResizable(false);
        ScreenUtil.centralizeFrame(testCaseFormWindow);
        testCaseFormWindow.setVisible(true);
        fillTestCaseForm();
    }

    public void closeTestCaseWindow() {
        testCaseFormWindow.setVisible(false);
    }

    public void closeTestCaseGenerationWindow() {
        testCaseGenerationWindow.setVisible(false);
    }

    public void openTestSuiteContentWindow(String s) {
        String tsid = s.substring("OPEN_TEST_SUITE_".length());
        testSuite = testSuites.getTestSuiteById(tsid);
        mainView.getPanelContainerSelected().removeAll();
        mainView.getPanelContainerSelected().add(testSuiteContentView, BorderLayout.CENTER);
        fillTestSuiteContentForm();
        mainView.getPanelContainerSelected().repaint();
        testSuiteContentView.setVisible(false);
        testSuiteContentView.setVisible(true);
    }

    public void emptyTestSuiteForm() {
        testSuiteFormView.getTextTestSuiteId().setEnabled(true);
        testSuiteFormView.getTextTestSuiteId().setText("");
        testSuiteFormView.getTextTestSuiteName().setText("");
        testSuiteFormView.getTextTestSuiteDescription().setText("");
        testSuiteFormView.getTextJDBCClass().setText(JDBC_CLASS_TEMPLATE);
        testSuiteFormView.getTextJDBCURL().setText(JDBC_URL_TEMPLATE);
        testSuiteFormView.getTextUsername().setText("");
        testSuiteFormView.getTextPassword().setText("");
        testSuiteFormView.getTextXMI().setText("");
    }

    public void fillTestSuiteForm() {
        // testsuite is the current test suite selected by user
        testSuiteFormView.getTextTestSuiteId().setEnabled(false);
        testSuiteFormView.getTextTestSuiteId().setText(testSuite.getId());
        testSuiteFormView.getTextTestSuiteName().setText(testSuite.getName());
        testSuiteFormView.getTextTestSuiteDescription().setText(testSuite.getDescription());
        testSuiteFormView.getTextJDBCClass().setText(testSuite.getDatabaseUnderTest().getClassName());
        testSuiteFormView.getTextJDBCURL().setText(testSuite.getDatabaseUnderTest().getUrl());
        testSuiteFormView.getTextUsername().setText(testSuite.getDatabaseUnderTest().getUserName());
        testSuiteFormView.getTextPassword().setText(testSuite.getDatabaseUnderTest().getPassword());
        testSuiteFormView.getTextXMI().setText(testSuite.getModel());
    }

    public void fillTestCaseForm() {
        // testcase is the current test case selected by user
        testCaseFormView.getTextTestCaseId().setEnabled(false);
        testCaseFormView.getTextTestCaseId().setText(testCase.getId());
        testCaseFormView.getTextTestCaseName().setText(testCase.getName());
        testCaseFormView.getTextTestCaseDescription().setText(testCase.getDescription());
        testCaseFormView.getTextTestCasePreCondition().setText(testCase.getPreCondition());
        testCaseFormView.getTextTestCasePosCondition().setText(testCase.getPosCondition());
        testCaseFormView.getTextTestCaseTestData().setText(testCase.getTestData().replaceAll(";", ";\n\r"));
        testCaseFormView.getTextTestCaseExpectedResults().setText(testCase.getExpectedResults());

        // history
        //for (TestLog)
    }

    public void fillTestSuiteContentForm() {
        String testSuiteDetails = "<html><font color=000075>#__id__<br>__name__<b></b></font></html>";
        testSuiteDetails = testSuiteDetails.replaceAll("__id__", testSuite.getId());
        testSuiteDetails = testSuiteDetails.replaceAll("__name__", testSuite.getName());
        testSuiteContentView.getTextTestSuiteDetails().setText(testSuiteDetails);

        updateTestSuiteStatus();
        buildTestCaseTable();
    }

    public void updateTestSuiteStatus() {
        testSuiteContentView.getTextPassRate().setText(StringUtil.formatNumber(testSuite.getPassRate(), "#0.0") + "%");
        testSuiteContentView.repaint();

        int totalPassed = 0, totalFailed = 0;
        String details = "<html><b>TOTAL:</b>&nbsp;Passed:&nbsp;<font color=#009900><b>__total.passed__</b></font>&nbsp;Failed:&nbsp;<font color=#990000><b>__total.failed__</b></font>";
        if (testSuite.getTestCycles().size() != 0) {
            for (TestLog log: testSuite.getTestCycles().get(testSuite.getTestCycles().size() - 1).getTestLogs()) {
                switch (log.getResult()) {
                    case PASSED: totalPassed++; break;
                    case FAILED: totalFailed++; break;
                }
            }
        }
        details = details.replaceAll("__total.passed__", totalPassed + "");
        details = details.replaceAll("__total.failed__", totalFailed + "");
        testSuiteContentView.getLabelTestCycleDetails().setText(details);

        loadTestSuites();
    }

    // methods

    public void deleteTestSuite() {

        if (DialogUtil.showWarningConfirmDialog("The selected Test Suite will be deleted.", "Do you to continue?") != JOptionPane.OK_OPTION)
            return;

        testService.deleteTestSuite(testSuite);
        mainView.getPanelContainerSelected().removeAll();

        loadTestSuites();
    }

    public void generateTestCases() {

        if (testSuite.getTestCases().size() > 0) {
            int result = DialogUtil.showInfoConfirmDialog("Test Case Generation.", "Test cases will be automatically generated from Database schema\n\nPrevious generated test cases will be permanently deleted.\n\nDo you want to continue?");
            if (result != JOptionPane.OK_OPTION) {
                return;
            }
        }

        testCaseGenerationWindow = new JFrame("Test Case Generation");
        testCaseGenerationWindow.setIconImage(mainView.getFrame().getIconImage());
        testCaseGenerationWindow.setBounds(250, 250, 1000, 700);
        ScreenUtil.centralizeFrame(testCaseGenerationWindow);
        testCaseGenerationWindow.getContentPane().add(testCaseGenerationView, BorderLayout.CENTER);
        testCaseGenerationWindow.setResizable(false);
        testCaseGenerationWindow.setVisible(true);
        testCaseGenerationView.getTextLog().append("Starting TEST CASE Generation...\n\n");
        testCaseGenerationView.getButtonAction().requestFocus();

        LoggerOutputStream loggerStream = new LoggerOutputStream(testCaseGenerationView.getTextLog());
        PrintStream logger = new PrintStream(loggerStream);

        try {
            testService.generateTestCases(testSuite, logger);
        } catch (Exception e) {
            DialogUtil.showErrorDialog("Test Case Generation error.", "It is not possible to create test cases from database schema specification.");
            return;
        }

        updateTestSuiteStatus();
        buildTestCaseTable();

        testService.updateTestSuite(testSuite);

        //DialogUtil.showInfoDialog("Test Cases created successfully.", "Test Cases have been created from Model Graph according to required elements.");
    }

    public void executeTestCases() {
        int result = DialogUtil.showInfoConfirmDialog("Test Case Execution is ready to start.", "A new test cycle will be created to log the results.\n\nDo you want to continue?");;
        if (result != JOptionPane.OK_OPTION) {
            return;
        }

        createTestCycle();

        // get the last test cycle to execute
        TestCycle testCycle = testSuite.getTestCycles().get(testSuite.getTestCycles().size() - 1);
        if (testCycle == null) {
            DialogUtil.showInfoDialog("There is no test cycle to execute.");
            return;
        }

        try {
            testDriver.executeTestCases(testSuite, testCycle);
        } catch (Exception e) {
            testSuite.getTestCycles().remove(testSuite.getTestCycles().size() - 1);
            DialogUtil.showErrorDialog("Test Execution error.", "An error has occured while trying to execute all test cases.\n\nError: " + e.getMessage());
        }

        testService.updateTestSuite(testSuite);

        updateTestSuiteStatus();
        buildTestCaseTable();
    }

    public void createTestCycle() {
        TestCycle testCycle = testDriver.createTestCycle(testSuite, testSuite.getTestCases());
        
        testSuite.getTestCycles().add(testCycle);
        testService.updateTestSuite(testSuite);

        buildTestCaseTable();
    }

    private boolean validateDatabase() {
        String jdbcClass, jdbcURL, username, password;
        jdbcClass = testSuiteFormView.getTextJDBCClass().getText().trim();
        jdbcURL = testSuiteFormView.getTextJDBCURL().getText().trim();
        username = testSuiteFormView.getTextUsername().getText().trim();
        password = testSuiteFormView.getTextPassword().getText().trim();

        testSuiteFormView.setDatabaseConnected(false);

        if ("".equals(jdbcClass)) {
            DialogUtil.showWarningDialog("JDBC Class is empty.", "Please, correct the field value before continuing.");
            testSuiteFormView.getTextJDBCClass().requestFocus();
            return false;
        }

        if ("".equals(jdbcURL)) {
            DialogUtil.showWarningDialog("JDBC URL is empty.", "Please, correct the field value before continuing.");
            testSuiteFormView.getTextJDBCURL().requestFocus();
            return false;
        }

        if ("".equals(username)) {
            DialogUtil.showWarningDialog("Username is empty.", "Please, correct the field value before continuing.");
            testSuiteFormView.getTextUsername().requestFocus();
            return false;
        }

        if ("".equals(username)) {
            DialogUtil.showWarningDialog("Password is empty.", "Please, correct the field value before continuing.");
            testSuiteFormView.getTextPassword().requestFocus();
            return false;
        }

        // try to load driver
        try {
            Class.forName(jdbcClass);
        } catch (Exception e) {
            DialogUtil.showErrorDialog("JDBC Class loading error.", "Error: " + e.getMessage() +  ".\n\nPlease, enter with a valid JDBC class name.");
            testSuiteFormView.getTextJDBCClass().requestFocus();
            return false;
        }

        // try to connect
        try {
            Connection conn = DriverManager.getConnection(jdbcURL, username, password);
            if (conn == null || conn.isClosed())
                throw new RuntimeException("Connection is NULL");
            conn.close();
        } catch (Exception e) {
            DialogUtil.showErrorDialog("JDBC Connection error.", "Error: " + e.getMessage() +  ".\n\nPlease, enter with a valid JDBC URL (server, port, database).");
            testSuiteFormView.getTextJDBCURL().requestFocus();
            return false;
        }

        testSuiteFormView.setDatabaseConnected(true);
        
        return true;
    }

    private void tryToConnectToDatabase() {
        if (!validateDatabase())
            return;
        DialogUtil.showInfoDialog("Database Connection has been done successfully.");
    }

    private boolean validateTestSuite() {
        String id = testSuiteFormView.getTextTestSuiteId().getText().trim();
        String name = testSuiteFormView.getTextTestSuiteName().getText().trim();
        String model = testSuiteFormView.getTextXMI().getText().trim();

        if ("".equals(id)) {
            DialogUtil.showWarningDialog("Invalid Test Suite Id.", "Please, correct the field value before continuing.");
            testSuiteFormView.getTextTestSuiteId().requestFocus();
            return false;
        }

        // check duplicate test suite id
        if (currentOperation == Operation.INSERT) {
            for (TestSuite ts: testSuites) {
                if (id.equals(ts.getId())) {
                    DialogUtil.showWarningDialog("Duplicate Test Suite Id.", "Please, try to enter with another value before continuing.");
                    testSuiteFormView.getTextTestSuiteId().requestFocus();
                    return false;
                }
            }
        }

        if ("".equals(name)) {
            DialogUtil.showWarningDialog("Test Suite Name is empty.", "Please, correct the field value before continuing.");
            testSuiteFormView.getTextTestSuiteName().requestFocus();
            return false;
        }

        if (!validateDatabase())
            return false;

        if ("".equals(model)) {
            DialogUtil.showWarningDialog("Model has not been selected.", "Please, select the XMI file which specifies the Database schema in UML.");
            testSuiteFormView.getButtonOpenXMIFile();
            return false;
        }

        return true;
    }

    private boolean validateTestCase() {
        String id = testCaseFormView.getTextTestCaseId().getText().trim();
        String name = testCaseFormView.getTextTestCaseName().getText().trim();

        if ("".equals(id)) {
            DialogUtil.showWarningDialog("Invalid Test Case Id.", "Please, correct the field value before continuing.");
            testCaseFormView.getTextTestCaseId().requestFocus();
            return false;
        }

        if ("".equals(name)) {
            DialogUtil.showWarningDialog("Test Case Name is empty.", "Please, correct the field value before continuing.");
            testCaseFormView.getTextTestCaseName().requestFocus();
            return false;
        }

        return true;
    }

    public void saveTestSuite() {
        if (!validateTestSuite())
            return;

        testSuite = currentOperation == Operation.INSERT ? new TestSuite() : testSuite;

        // test suite
        testSuite.setId(testSuiteFormView.getTextTestSuiteId().getText().trim());
        testSuite.setName(testSuiteFormView.getTextTestSuiteName().getText().trim());
        testSuite.setDescription(testSuiteFormView.getTextTestSuiteDescription().getText().trim());
        testSuite.setAuthor("");
        testSuite.setAddedOn(new Date());
        // db under test
        testSuite.getDatabaseUnderTest().setClassName(testSuiteFormView.getTextJDBCClass().getText().trim());
        testSuite.getDatabaseUnderTest().setUrl(testSuiteFormView.getTextJDBCURL().getText().trim());
        testSuite.getDatabaseUnderTest().setUserName(testSuiteFormView.getTextUsername().getText().trim());
        testSuite.getDatabaseUnderTest().setPassword(testSuiteFormView.getTextPassword().getText().trim());
        // model
        testSuite.setModel(testSuiteFormView.getTextXMI().getText());

        // save
        testSuite = testService.insertTestSuite(testSuite);
        testSuites.add(testSuite);

        // load test suites
        loadTestSuites();

        closeTestSuiteWindow();

        //DialogUtil.showInfoDialog("Test Suite has been added successfully.");
    }

    public void loadTestSuites() {
        int i = 0;
        testSuites = testService.getAllTestSuites();
        mainView.getPanelContainerList().removeAll();
        mainView.getPanelTestSuiteList().removeAll();

        if (testSuites.size() == 0) {
            JLabel label = new JLabel("No test suites", JLabel.CENTER);
            label.setForeground(new Color(125, 125, 125));
            label.setBounds(1, 1, 333, 25);
            mainView.getPanelTestSuiteList().add(label);
        }
        
        for (TestSuite ts: testSuites) {
            int height = 65;
            TestSuiteItemTemplateView template = new TestSuiteItemTemplateView(ts, this);
            template.setBounds(1, height * i + 1, 333, height - 1);
            template.repaint();
            mainView.getPanelTestSuiteList().add(template);
            i++;
        }
        mainView.getPanelContainerList().add(mainView.getPanelTestSuiteListContainer(), BorderLayout.CENTER);
        mainView.getMainPanel().repaint();
        mainView.getMainPanel().setVisible(false);
        mainView.getMainPanel().setVisible(true);
    }

    public void saveTestCase() {
        if (!validateTestCase())
            return;

        testCase.setId(testCaseFormView.getTextTestCaseId().getText().trim());
        testCase.setName(testCaseFormView.getTextTestCaseName().getText().trim());
        testCase.setDescription(testCaseFormView.getTextTestCaseDescription().getText().trim());
        testCase.setPreCondition(testCaseFormView.getTextTestCasePreCondition().getText().trim());
        testCase.setPosCondition(testCaseFormView.getTextTestCasePosCondition().getText().trim());
        testCase.setTestData(testCaseFormView.getTextTestCaseTestData().getText().trim());
        testCase.setExpectedResults(testCaseFormView.getTextTestCaseExpectedResults().getText().trim());

        // save
        testSuite = testService.updateTestSuite(testSuite);

        // fill test suite form
        fillTestSuiteContentForm();

        closeTestCaseWindow();
    }

    public void openXMIFile() {
        int result = testSuiteFormView.getFileChooser().showSaveDialog(testSuiteFormView);
        if (result != JFileChooser.APPROVE_OPTION)
            return;

        String fileName = testSuiteFormView.getFileChooser().getSelectedFile().getAbsolutePath();
        File file = new File(fileName);

        if (!file.exists()) {
            DialogUtil.showErrorDialog("XMI File error.", "The entered XMI file does not exist.\n\nFile: " + file.getAbsolutePath());
            return;
        }

        try {
            ScreenUtil.setWaitCursor(testSuiteContentView);
            String line = "";
            BufferedReader reader = new BufferedReader(new FileReader(file));
            while ((line = reader.readLine()) != null) {
                testSuiteFormView.getTextXMI().append(line + "\n");
            }
            reader.close();
            ScreenUtil.setDefaultCursor(testSuiteContentView);
        } catch (Exception e) {
            ScreenUtil.setDefaultCursor(testSuiteContentView);
            DialogUtil.showErrorDialog("XMI File error.", "An error has occurred while trying to read XMI file.\n\nError: " + e.getMessage());
        }
    }

    // model
    public void buildTestCaseTable() {
        
        if (testSuite == null || testSuite.getTestCases().size() == 0)
            return;

        boolean addComments = testSuite.getTestCycles().size() > 0;
        int i = 0, cycleCount = 0;
        int headersLen = 2 + testSuite.getTestCycles().size() + (addComments ? 1 : 0);
        String[] headers = new String[headersLen];

        headers[i++] = "ID";
        headers[i++] = "Description";
        for (TestCycle cycle: testSuite.getTestCycles()) {
            headers[i++] = "Cycle" + (++cycleCount);
        }
        if (addComments) {
            headers[i++] = "Comments";
        }
        
        int row = 0, col = 0;
        TableModel model = new TestCaseTableModel(testSuite.getTestCases().size(), headers);
        for (TestCase tc: testSuite.getTestCases()) {
            col = 0; String comments = "";
            model.setValueAt(tc.getId(), row, col++);
            model.setValueAt(tc.getName(), row, col++);
            for (TestCycle cycle: testSuite.getTestCycles()) {
                for (TestLog log: cycle.getTestLogs()) {
                    if (log.getTestCase().getId().equals(tc.getId())) {
                        String result = "?";
                        switch(log.getResult()) {
                            case PASSED: result = "<html><b><span style='border:0px;background-color:green;'><font face='lucida console' color=white>&nbsp;&nbsp;&nbsp;P&nbsp;&nbsp;&nbsp;"; break;
                            case FAILED: result = "<html><b><span style='border:0px;background-color:red;'><font face='lucida console' color=white>&nbsp;&nbsp;&nbsp;F&nbsp;&nbsp;&nbsp;"; break;
                        }
                        model.setValueAt(result, row, col);
                        comments = log.getComments();
                    }
                }
                col++;
            }
            if (addComments) {
                model.setValueAt(comments, row, col++);
            }
            row++;
        }
        testSuiteContentView.getTableTestCases().setModel(model);
        TableColumn column = null;
        for (int cx = 0; cx < col; cx++) {
            int w = 0;
            column = testSuiteContentView.getTableTestCases().getColumnModel().getColumn(cx);
            if (cx == 0) {
                w = 40;
            } else if (cx == 1) {
                w = addComments ? 500 : 800;
            } else if (cx == headersLen - 1 && addComments) {
                w = 1000;
            } else {
                w = 61;
            }
            column.setPreferredWidth(w);
            column.setWidth(w);
        }
        // table double click to open test case
        ListSelectionModel listMod =  testSuiteContentView.getTableTestCases().getSelectionModel();
        listMod.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        listMod.addListSelectionListener(this);
        testSuiteContentView.getTableTestCases().addMouseListener(new MouseAdapter(){
            @Override
            public void mouseClicked(MouseEvent e){
                if (e.getClickCount() == 2){
                    openTestCaseWindow();
                }
            }
        });
    }

    // ListSelectionListener
    //
    public void valueChanged(ListSelectionEvent e) {
        int maxRows;
        int[] selRows;
        Object value;

        if (!e.getValueIsAdjusting()) {
            selRows = testSuiteContentView.getTableTestCases().getSelectedRows();

            if (selRows.length > 0) {
                TableModel tm = testSuiteContentView.getTableTestCases().getModel();
                value = tm.getValueAt(selRows[0], 0);
                // set selected test case
                testCase = testSuite.getTestCases().getTestCaseById(value.toString());
            }
        }
    }

    // ActionListener
    //
    public void actionPerformed(ActionEvent e) {

        String command = e.getActionCommand();

        if (command == null || "".equals(command)) {
            return;
        } else if (CREATE_TEST_SUITE_ACTION.equals(command)) {
            openTestSuiteWindow(Operation.INSERT);
        } else if (TEST_CONNECTION_ACTION.equals(command)) {
            tryToConnectToDatabase();
        } else if (OPEN_XMI_FILE_ACTION.equals(command)) {
            openXMIFile();
        } else if (SAVE_TEST_SUITE_ACTION.equals(command)) {
            saveTestSuite();
        } else if (CANCEL_TEST_SUITE_ACTION.equals(command)) {
            closeTestSuiteWindow();
        } else if (EDIT_TEST_SUITE_ACTION.equals(command)) {
            openTestSuiteWindow(Operation.UPDATE);
        } else if (DELETE_TEST_SUITE_ACTION.equals(command)) {
            deleteTestSuite();
        } else if (GENERATE_TEST_CASES_ACTION.equals(command)) {
            generateTestCases();
        } else if (EXECUTE_TEST_CASES_ACTION.equals(command)) {
            executeTestCases();
        } else if (TEST_CASE_GENERATION_DONE_ACTION.equals(command)) {
            closeTestCaseGenerationWindow();
        } else if (SAVE_TEST_CASE_ACTION.equals(command)) {
            saveTestCase();
        } else if (CANCEL_TEST_CASE_ACTION.equals(command)) {
            closeTestCaseWindow();
        } else if (command.startsWith("OPEN_TEST_SUITE_")) {
            openTestSuiteContentWindow(command);
        }
    }

    public void handleTestRun(TestCase testCase, TestResult testResult) {
        System.out.println("Test Case Execution: " + testCase.getId() + ", Result: " + testResult);
        buildTestCaseTable();
    }

}
